Date: Thu, 25 Feb 1993 10:05:00 -0800 From: seth%CAMP@onet.edu To: MOO-Cows.parc@xerox.com Subject: Re: Permissions system of moo Wayne / Sadric: > Um, Seth, from what I gather, the whole point of allowing corporations > is so that non-players can own verbs. Therefore they don't HAVE to have > a player flag. Thus eliminating the problem you stated. I see... I admit, though, that I'm not entirely clear on why non-players have to own verbs. yduJ alluded to a problem before, but it wasn't one I'd seen previously. I'm gonna spout off on what I think the Right Way to do group projects is (aside from having a shared character to hack with). Actually, I was asked to send some more details about our corified multiple ownership on OpalMOO. It all revolves around a hacker-owned !c property on $root_class -- .owners, defaulting to {}. The main verbs in the DB permitted to directly change this property are $ownership_utils:add_owner and $ownership_utils:delete_owner. The only other verb which is permitted to change this property is the all- important $ownership_utils:controls verb, which reads as follows (it, like the two previously-mentioned verbs, is Hacker-owned): $ownership_utils:controls this none this rx 1: "$ownership_utils:controls(who, what)"; 2: "is WHO allowed to hack on WHAT?"; 3: "YES if WHO is WHAT's owner."; 4: "YES if WHO is a wizard."; 5: "YES if WHO is one of WHAT's shared owners listed in the .owners prop"; 6: "NO otherwise."; 7: "This verb also maintains the purity of .owners by ensuring that it is never clear and only contains living players."; 8: "Because of the twisted way in which !d verbs blindly march forward through errors, this verb -will- properly handle objects which do not have .owners properties (assuming that the correct answer in that case is `Yes if you're a wizard or you own it')."; 9: who = args[1]; 10: what = args[2]; 11: if (is_clear_property(what, "owners")) 12: "there's a fukd-up :initialize SOMEWHERE"; 13: what.owners = {}; 14: return 0; 15: endif 16: for dude in (what.owners) 17: if (!valid(dude) || !is_player(dude)) 18: what.owners = setremove(what.owners, dude); 19: endif 20: endfor 21: if (who.wizard || who == what.owner || who in what.owners) 22: return 1; 23: else 24: return 0; 25: endif 26: "Last modified Mon Feb 8 23:53:32 1993 EST by BabyBriar (#2)."; The $ownership_utils:controls() check is essentially the same as the older $perm_utils:controls() check, except that it takes into account the extra possible owners and it also handles the special cases needed to maintain security. This verb is called to determine whether a player is permitted to, say, add a verb to any given object. Here is the code called when someone wants to add a verb to an object: $ownership_utils:add_verb this none this rx Wizard 1: "add_verb() -- see help on the builtin for more information"; 2: who = caller_perms(); 3: what = args[1]; 4: info = args[2]; 5: vargs = args[3]; 6: if (!$ownership_utils:controls(who, what) && !what.w) 7: "caller_perms() is not allowed to hack on the object in question"; 8: return E_PERM; 9: elseif (!$perm_utils:controls(who, info[1])) 10: "caller_perms() is not permitted to add a verb with the specified owner."; 11: return E_PERM; 12: else 13: "we now know that the caller's perms control the object (by multiple inheritance) or the object is writable, and we know that the caller's perms control the prospective verb owner (by more traditional means)"; 14: return add_verb(@args); 15: endif (Yes, I know it's not the best-written code in the world, but it works.) Essentially, this allows a player to add a verb to any object e controls (or any writable object, for that matter). (The reason I include this example is because I will refer to it later on.) With these sort of controls in place, it's easy to add similar verbs for the other relevant builtins (add_property, verb_args, etc.). There are a few tricks that need to be handled, though: 1. How do we handle shared verbs? 2. How do we handle shared properties? 3. How do we handle shared PLAYERS? (this last one has special promise) There are a few ways we looked at to handle shared verbs. One of them was to stick with the old server-style method of setting verb code, and only allowing someone to set code on a verb e owns eirself. This was shot down primarily because it was clunky and didn't let people collaborate so well. Another method was to let any owner of a shared object set the code on any verb on that object. This got shot down -real- fast because nobody liked the idea that by sharing an object, people could make tasks run with their own permissions. The last method, the one we settled on, was to have the verb ownership change when the code is changed. Here is the code we're using: $ownership_utils:set_verb_code this none this rx Wizard 1: who = caller_perms(); 2: where = args[1]; 3: what = args[2]; 4: code = args[3]; 5: while ((last = code[length(code)]) && length(last) >= 15 && last[1..15] == "\"Last Modified ") 6: code = code[1..length(code) - 1]; 7: endwhile 8: args[3] = {@code, tostr("\"Last modified ", ctime(), " by ", who.name, " (", who, ").\";")}; 9: if ($ownership_utils:controls(who, where) && !who.wizard) 10: "the player controls the object in question AND IS NOT WIZARDLY"; 11: info = verb_info(where, what); 12: if (typeof(info) == ERR) 13: "most likely, verb not exists"; 14: return info; 15: endif 16: info[1] = who; 17: set_verb_info(where, what, info); 18: endif 19: set_task_perms(who); 20: return set_verb_code(@args); 21: "Last modified Mon Feb 15 23:04:40 1993 EST by BabyBriar (#2)."; This code changes the owner to the new editor, if that editor is non- wizardly. This has been found to be a quite suitable arrangement. Handling properties proved to be a different animal, so we needed to introduce two new `builtins' -- property_value and set_property_value. Essentially, the only added functionality they offered was that a !c property defined on a shared object could be used (set, read, etc.) by any of the owners of that object, even when that property is being accessed on a descendant. As an example: $ownership_utils:property_value this none this rx Wizard 1: "$ownership_utils:property_value( object , property-name ) => value | E_PERM | E_PROPNF"; 2: who = caller_perms(); 3: where = args[1]; 4: what = args[2]; 5: if (typeof(where) != OBJ) 6: return E_INVARG; 7: elseif (!valid(where)) 8: return E_INVARG; 9: elseif (typeof(what) != STR) 10: return E_INVARG; 11: endif 12: info = property_info(where, what); 13: if (typeof(info) == ERR) 14: return info; 15: endif 16: if (index(info[2], "r") || $perm_utils:controls(who, info[1])) 17: return where.(what); 18: endif 19: "now for the TRICKY part. The property is not readable by our caller's permissions. Is it defined on an object which the caller controls?"; 20: home = $ownership_utils:property_definition(where, what); 21: if ($ownership_utils:controls(who, home) && !index(info[2], "c")) 22: return where.(what); 23: endif 24: "last shot -- is there anything I missed?"; 25: set_task_perms(who); 26: return where.(what); The last question is one we're not yet facing on OpalMOO, but one I intend to introduce soon. What if the object being shared is not merely an object, but in fact a -player- object? What I intend to do soon is eliminate the $perm_utils checks and use $ownership_utils totally. What this will mean, essentially, is that we will have a situation like the following: Munchkin and Xiombarg are working on some hellish projects together, and they trust each other a lot. So Xiombarg, being the more trusting of the two, adds Munchkin as an owner to HERSELF -- so that, essentially, Xiombarg is a player object with two owners. Munchkin is now able to execute the previously-unavailable commands: @verb foo:bar this none this rxd Xiombarg @property foo.baz {} "r" Xiombarg ... and, thus, create verbs and properties owned by Xiombarg, by virtue of his being an owner of hers. (Eek, I realize I've painted this in a horribly sexist way. Let's assume that at this point in the text Xiombarg morphs into Xiombargs, so they're plural now.) Similarly, although this isn't supported by the above code, Munchkin will be able to set the code on Xiombargs-owned verbs, and essentially do anything except actually log in as the Xiombargs (because this still doesn't allow access to the password). (Because of this upcoming development, $ownership_utils:add_owner does not allow an owner to be added to a wizardly object.) We're going through the database and changing most of the core verbs to use these multiple ownership utilities. So far, we've had very few bugs (although some people griped about the verb timestamping). I think that this method allows for simpler handling of shared projects. Seth / Blackbriar